package com.wwd.common;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.wwd.common.annotation.Lockable;
import com.wwd.common.lock.RedisLock;


@Aspect
@Component
public class LockAspectConfig {
	
	Logger logger = LoggerFactory.getLogger(LockAspectConfig.class);
	
	@Autowired
	private RedisLock redisLock;

	@Pointcut("@annotation(com.wwd.common.annotation.Lockable)")
	public void lockablePointcut() {}
	
	@Around("lockablePointcut()")
	public Object tryLock(ProceedingJoinPoint pjp) {
		Signature signature = pjp.getSignature();
		MethodSignature methodSignature = (MethodSignature)signature;
		Method method = methodSignature.getMethod();
		String targetName = pjp.getTarget().getClass().getName();
		Object[] args = pjp.getArgs();
		Lockable lockable= method.getAnnotation(Lockable.class);
		long expiration = lockable.expiration();
		String key = getRedisKey(method.getName(),targetName,lockable.keys(),args);
		int retry = lockable.retry();
		boolean lock = redisLock.lock(key,expiration,retry);
		if(!lock) {
			logger.info("get lock failed");
			return null;
		}
		try {
			return pjp.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}finally{
			boolean release = redisLock.unlock(key);
			if(release) {
				logger.info("relsease lock " + key + " succeeded");
			}else {
				logger.info("relsease lock " + key + " failed");
			}
		}
		return null;
	}
	
	private String getRedisKey(String methodName,String targetName,String[] keys,Object[] params) {
		StringBuilder redisKey = new StringBuilder();
		redisKey.append("lock.").append(methodName).append(".").append(targetName);
		if(keys != null && keys.length > 0) {
			for(String k:keys) {
				redisKey.append(".");
				redisKey.append(k);
			}
		}
		return redisKey.toString();
	}
}
